package top.callback.inf.beautyleaf.common.thread;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.*;

/**
 * 对原生线程池的扩展，添加了监控日志。
 *
 * @author Pengyu Gan
 * Created 2021/3/23
 */
public class MonitoredThreadPool extends ThreadPoolExecutor {

    private static final Logger log = LoggerFactory.getLogger(MonitoredThreadPool.class);

    /**
     * 线程启动时间
     */
    private ConcurrentHashMap<String, LocalDateTime> startTimes;

    /**
     * 线程池名称
     */
    private String threadPoolName;

    public MonitoredThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime,
                               TimeUnit unit, BlockingQueue<Runnable> workQueue, String threadPoolName) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                new NamedThreadFactory(threadPoolName), threadPoolName);
    }

    public MonitoredThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime,
                               TimeUnit unit, BlockingQueue<Runnable> workQueue,
                               ThreadFactory threadFactory, String threadPoolName) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
        this.startTimes = new ConcurrentHashMap<>();
        this.threadPoolName = threadPoolName;
    }

    @Override
    public void shutdown() {
        log.debug("线程池 {} 准备关闭。已处理任务数：{}，正在运行任务数：{}，等待任务数：{}",
                threadPoolName, this.getCompletedTaskCount(), this.getActiveCount(), this.getQueue().size());
        super.shutdown();
    }

    @Override
    public List<Runnable> shutdownNow() {
        log.debug("线程池 {} 强制立即关闭。已处理任务数：{}，正在运行任务数：{}，等待任务数：{}",
                threadPoolName, this.getCompletedTaskCount(), this.getActiveCount(), this.getQueue().size());
        return super.shutdownNow();
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        startTimes.put(String.valueOf(r.hashCode()), LocalDateTime.now());
        super.beforeExecute(t, r);
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        LocalDateTime startTime = startTimes.remove(String.valueOf(r.hashCode()));
        LocalDateTime finishTime = LocalDateTime.now();
        Duration duration = Duration.between(startTime, finishTime);
        log.debug("线程池 {} 监控信息：" +
                        "本次任务耗时: {} ms, 当前线程数: {}, 核心线程数: {}, 正在运行任务数: {}, " +
                        "已处理任务数: {}, 任务总数: {}, 等待任务数: {}, 最大持有过的线程数: {}, " +
                        "最大线程数: {},  空闲线程存活时长: {} ms, 线程池已关闭: {}, 线程池已停止: {}",
                threadPoolName,
                duration.toMillis(), this.getPoolSize(), this.getCorePoolSize(), this.getActiveCount(),
                this.getCompletedTaskCount(), this.getTaskCount(), this.getQueue().size(), this.getLargestPoolSize(),
                this.getMaximumPoolSize(), this.getKeepAliveTime(TimeUnit.MILLISECONDS), this.isShutdown(), this.isTerminated());
        super.afterExecute(r, t);
    }

}